home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / t3_1 / doc.lha / documentation / manual / operation.mss < prev    next >
Text File  |  1987-06-30  |  14KB  |  342 lines

  1. @part[OPERATIONS, Root "TMAN.MSS"]      @Comment{-*-System:TMAN-*-}
  2. @chap[Operations]
  3. @label[OperationsChapter]       @Comment{ref: structure chapter}
  4.  
  5.  
  6. @Tau[] provides a simple mechanism for programming in what
  7. has come to be known as the @i[object-oriented style] of programming.
  8. Object-oriented style may be contrasted to what will here be called
  9. @i[procedural style].  In object-oriented programming, programs are
  10. organized by giving the behavior of objects when various operations
  11. are applied to them, whereas in procedural style, programs are organized
  12. by giving the behavior of procedures when applied to various kinds
  13. of objects.  These styles are equivalent in terms of computational
  14. power, but each offers different advantages in terms of readability
  15. and modularity.
  16.  
  17. @Tau[] supports the object-oriented style with a special kind of procedure
  18. known as an @iixs[operation], and with forms which permit one to create
  19. objects which exhibit certain behavior when a given operation is applied
  20. to them.
  21.  
  22. When an operation is called, the following sequence of events occurs:
  23. @begin[itemize]
  24. A @iixs[handler] is obtained for the object which was the operation's
  25. first argument.  (Operations must always be called with at least one argument.)
  26.  
  27. The operation asks the handler for a @iixs[method] which will handle the
  28. operation for the object.
  29.  
  30. The handler either provides a method, or it indicates that the
  31. object is not prepared to handle the operation.
  32.  
  33. If the handler provided a method, the method is invoked.
  34. If not, then the operation's @iixs[default method], if any, is invoked.
  35. If the operation has no default method, then the effect of the call to the
  36. operation is undefined (and presumably an error condition is signalled).
  37. @end[itemize]
  38.  
  39. In this way, an object's handler may determine how the operation
  40. is to be performed for the object @dash[] that is, which particular method
  41. is to be invoked as a result of invoking the operation.
  42.  
  43. Handlers map operations to methods.  Many objects may have the same
  44. handler, or a handler may be idiosyncratic to a particular object.
  45. However, @i[every] object has a handler, so all objects participate in the
  46. generic operation dispatch protocol.
  47.  
  48. @section[Fundamental forms]
  49.  
  50. The basis of the generic operation system consists of the two special
  51. forms @tc[OBJECT] and @tc[OPERATION].  @tc[OBJECT]-expressions create
  52. objects which respond appropriately to generic operations, and
  53. @tc[OPERATION]-expressions evaluate to operations.
  54. @index[Objects]
  55.  
  56. @info[NOTES="Special form"]
  57. @desc[(OBJECT @i[procedure] . @i[method-clauses]) @yl[] @i[object]]
  58.  
  59. An @tc[OBJECT]-expression yields an object which is prepared to handle
  60. generic operations according to the @i[method-clauses].
  61. In the following description, @qu"the object" refers
  62. to the value of a given @tc[OBJECT]-expression.
  63.  
  64. Each @i[method-clause] should be of the form
  65.   @begin[ProgramExample]
  66. ((@i[operation] . @i[variables]) . @i[body])
  67.   @end[ProgramExample]
  68. @i[Operation] is an evaluated position, and is typically a variable
  69. which evaluates to an operation, although it may be any
  70. expression.  When an operation is called with the object as its first
  71. argument, the @i[operation]-expressions are evaluated,
  72. and if one yields the operation being applied to the object, the corresponding
  73. @i[method-clause] is selected.  The operation is then performed
  74. according to the selected @i[method-clause]: the clause's @i[variables]
  75. are bound to the arguments to the operation,
  76. and its @i[body], an implicit block, is evaluated.
  77.   @begin[ProgramExample]
  78. (DEFINE OP (OPERATION NIL))
  79. (OP (OBJECT NIL ((OP SELF) 34)))      @ev[]  34
  80. (OP (OBJECT NIL ((OP SELF X) X)) 55)  @ev[]  55
  81.   @end[ProgramExample]
  82.  
  83. @i[Procedure] may be any expression, and is evaluated at the time the
  84. @tc[OBJECT]-expression is evaluated.  The object, when called, simply
  85. calls the value of the @i[procedure] expression, passing on any
  86. arguments.  Typically @i[procedure] might be either a
  87. @tc[LAMBDA]-expression, if the object is to be callable, or it is
  88. @tc[NIL], which by convention means that the object is not intended to
  89. be called, the value of @tc[NIL] being an uncallable object.
  90.  
  91. In the degenerate case, where there are no method clauses, the value of
  92.   @begin[ProgramExample]
  93. (OBJECT (LAMBDA @i[args] . @i[body]))
  94.   @end[ProgramExample]
  95. is indistinguishable from that of
  96.   @begin[ProgramExample]
  97. (LAMBDA @i[args] . @i[body])@r[.]
  98.   @end[ProgramExample]
  99.  
  100. The semantics of the @tc[OBJECT] and @tc[OPERATION] special forms
  101. can be described in terms of hypothetical primitive procedures
  102. @tc[*OBJECT] and @tc[GET-HANDLER].
  103. These primitives do not actually
  104. exist in @Tau[], but are introduced here as expository aids.
  105. @tc[*OBJECT] takes two arguments, and returns an object which, when
  106. called, calls the object which was @tc[*OBJECT]'s first argument, and
  107. when given to @tc[GET-HANDLER] returns the object which was
  108. @tc[*OBJECT]'s second argument.  That is,
  109. @tc[*OBJECT] creates a two-component record (like a pair),
  110. @tc[GET-HANDLER] extracts one component, and the other component is
  111. called when the record is called.
  112.   @begin[ProgramExample]
  113. @tabclear
  114. (GET-HANDLER (*OBJECT @i[proc handler]))  @^@ce[]  @i[handler]
  115. ((*OBJECT @i[proc] @i[handler]) @i[arg] ...)  @\@ce[]  (@i[proc] @i[arg] ...)
  116. @tabclear
  117.   @end[ProgramExample]
  118. In addition, @tc[GET-HANDLER] is defined on @i[all] objects to return
  119. some handler, even objects not created by @tc[*OBJECT] (if indeed
  120. there are any such objects).
  121.  
  122. Given these primitives, the following rough equivalence holds:
  123.   @begin[ProgramExample]
  124. (OBJECT @i[proc]
  125.         ((@i[op@-[1]] . @i[args@-[1]]) . @i[body@-[1]])
  126.         ((@i[op@-[2]] . @i[args@-[2]]) . @i[body@-[2]])
  127.         ...
  128.         ((@i[op@-[n]] . @i[args@-[n]]) . @i[body@-[n]]))
  129.   @ce[]
  130. (*OBJECT @i[proc]
  131.          (LAMBDA (OP)
  132.            (SELECT OP
  133.              ((@i[op@-[1]]) (LAMBDA @i[args@-[1]] . @i[body@-[1]]))
  134.              ((@i[op@-[2]]) (LAMBDA @i[args@-[2]] . @i[body@-[2]]))
  135.              ...
  136.              ((@i[op@-[n]]) (LAMBDA @i[args@-[n]] . @i[body@-[n]]))
  137.              (ELSE NIL))))
  138.   @end[ProgramExample]
  139. The outer @tc[LAMBDA]-expression yields the object's handler;
  140. the inner @tc[LAMBDA]-expressions yield the methods, and
  141. the mapping from operations to methods is accomplished by
  142. the @tc[SELECT]-expression (see @tc[SELECT], page @pageref[SELECT]).
  143. Note that the syntactic positions
  144. @i[op@-[1]],
  145. @i[op@-[2]],
  146. ...
  147. @i[op@-[n]]
  148. are evaluated positions, and the operation expressions
  149. are evaluated when an operation is applied to the object,
  150. not when the object is created.
  151. @EndDesc[OBJECT]
  152.  
  153. @info[NOTES="Special form"]
  154. @desc[(OPERATION @i[default] . @i[method-clauses]) @yl[] @i[operation]]
  155. The syntax of @tc[OPERATION] is the same as that of @tc[OBJECT], but its
  156. semantics and application are somewhat different.  An
  157. @tc[OPERATION]-expression evaluates to an operation.  When called, the
  158. operation obtains a handler for its first argument, calls the handler to
  159. obtain a method, and then invokes the method.  The default method for
  160. the operation is established as being @i[default].
  161.  
  162. As the subject of another generic operation, an operation is an object
  163. like any other, and in this case the operation acts just as if it had
  164. been created by an @tc[OBJECT]-expression with the same @i[method-clauses].
  165. In this way one can establish the behavior of an operation
  166. when subject to other operations, for example @tc[SETTER].
  167.  
  168. The following rough equivalence describes the semantics of @tc[OPERATION].
  169. Some details have been omitted.
  170.   @begin[ProgramExample]
  171. (OPERATION @i[default] . @i[methods])
  172.   @ce[]
  173. (LABELS ((OP (OBJECT (LAMBDA (OBJ . ARGS)
  174.                        (LET ((METHOD ((GET-HANDLER OBJ) OP)))
  175.                          (COND (METHOD
  176.                                 (APPLY METHOD OBJ ARGS))
  177.                                (ELSE
  178.                                 (APPLY @i[default] OBJ ARGS)))))
  179.                      . @i[methods])))
  180.   OP)
  181.   @end[ProgramExample]
  182. For example:
  183.   @begin[ProgramExample]
  184. (DEFINE OP (OPERATION (LAMBDA (OBJ) 'ZEBU)))
  185. (OP (OBJECT NIL ((OP SELF) 'QUAGGA)))  @ev[]  QUAGGA
  186. (OP 'ELAND)                            @ev[]  ZEBU
  187.   @end[ProgramExample]
  188. An operation is created, and the variable @tc[OP] is bound to it.
  189. The operation's default method always returns the symbol @tc[ZEBU].
  190. When the operation is applied to the value of the @tc[OBJECT]-expression,
  191. the appropriate method is invoked, and the call to the operation yields
  192. the symbol @tc[QUAGGA].  When the operation is applied to an object
  193. which doesn't handle it @dash[] the symbol @tc[ELAND] @dash[] the operation's
  194. default method is invoked, so the call yields the symbol @tc[ZEBU].
  195. @EndDesc[OPERATION]
  196.  
  197. @info[NOTES="Type predicate"]
  198. @desc[(OPERATION? @i[object]) @yl[] @i[boolean]]
  199. Returns true if @i[object] is an operation.
  200. @EndDesc[OPERATION?]
  201.  
  202.  
  203. @section[Defining operations]
  204.  
  205. @info[NOTES="Special form"]
  206. @desc[(DEFINE-OPERATION (@i[variable] . @i[argument-vars]) . @i[body]) @yl[] @i[undefined]]
  207. Defines @i[variable] to be an operation.
  208. The syntax is intended to be analogous to that of @tc[DEFINE].
  209. The operation's default method is defined by @i[argument-vars] and @i[body].
  210. If there is no @i[body], then the operation's default method
  211. is undefined.  In this case, the @i[argument-vars]
  212. appear only for documentary purposes.
  213.   @begin[ProgramExample]
  214. (DEFINE-OPERATION (@i[var] . @i[args]) . @i[body])
  215.   @ce[]  (DEFINE @i[var] (OPERATION (LAMBDA @i[args] . @i[body])))
  216.  
  217. (DEFINE-OPERATION (@i[var] . @i[args]))
  218.   @ce[]  (DEFINE @i[var] (OPERATION UNDEFINED-EFFECT))
  219.   @end[ProgramExample]
  220. @EndDesc[DEFINE-OPERATION]
  221.  
  222. @info[NOTES="Special form"]
  223. @desc[(DEFINE-SETTABLE-OPERATION (@i[variable] . @i[argument-vars]) . @i[body]) @yl[] @i[undefined]]
  224. Defines @i[variable] to be an operation, as with @tc[DEFINE-OPERATION],
  225. but arranges for the operation's @qu"setter" to be another operation,
  226. so that the operation is @qu"settable" (see page @pageref[Settable]).
  227.   @begin[ProgramExample]
  228. (DEFINE-SETTABLE-OPERATION (@i[var] . @i[args]) . @i[body])
  229.   @ce[]
  230. (DEFINE @i[var]
  231.   (LET ((THE-SETTER (OPERATION UNDEFINED-EFFECT)))
  232.     (OPERATION (LAMBDA @i[args] . @i[body])
  233.       ((SETTER SELF) THE-SETTER))))
  234.   @end[ProgramExample]
  235. @EndDesc[DEFINE-SETTABLE-OPERATION]
  236.  
  237. @info[NOTES="Special form"]
  238. @desc[(DEFINE-PREDICATE @i[variable]) @yl[] @i[undefined]]
  239. Defines @i[variable] to be an operation which, by default,
  240. returns false.
  241.   @begin[ProgramExample]
  242. (DEFINE-PREDICATE @i[var])
  243.   @ce[]
  244. (DEFINE-OPERATION (@i[var] OBJ) NIL)
  245.   @end[ProgramExample]
  246.  
  247. The intent is that particular @tc[OBJECT]-expressions contain clauses
  248. of the form @wt[((@i[variable] SELF) T)].  This way the operation
  249. defined by @tc[DEFINE-PREDICATE] may act as a type predicate that returns
  250. true only for those objects returned by such @tc[OBJECT]-expressions.
  251. @EndDesc[DEFINE-PREDICATE]
  252.  
  253. @dc{ Talk about how to use @tc[OBJECT] to define @qu"types." }
  254.  
  255.  
  256. @section[Joined objects]
  257.  
  258. @desc[(JOIN . @i[objects]) @yl[] @i[joined-object]]
  259. @tc[JOIN] returns an object, called a @iixs[joined object], whose
  260. behavior is a combination of the behaviors of the @i[objects].  When an
  261. operation is applied to the joined object, each @i[object] in turn is
  262. given an opportunity to handle the operation; the first
  263. to handle it does so.
  264.   @begin[ProgramExample]
  265. (JOIN (OBJECT @i[proc@-[1]] @i[method@-[11] method@-[12] ...])
  266.       (OBJECT @i[proc@-[2]] @i[method@-[21] method@-[22] ...]))
  267.   @ce[]
  268. (OBJECT @i[proc@-[1]] @i[method@-[11] method@-[12] ...] @i[method@-[21] method@-[22] ...])
  269.   @end[ProgramExample]
  270. Using the hypothetical primitives described earlier, @tc[JOIN]
  271. could be defined by the following:
  272.   @begin[ProgramExample]
  273. (JOIN @i[first] @i[second])
  274.   @ce[]
  275. (*OBJECT @i[first]
  276.          (LAMBDA (OP)
  277.            (OR ((GET-HANDLER @i[first]) OP)
  278.                ((GET-HANDLER @i[second]) OP))))
  279.   @end[ProgramExample]
  280.     @BeginInset[Bug:]
  281.     @Timp[] 2.7 doesn't implement @tc[JOIN].
  282.     @EndInset[]
  283. @EndDesc[JOIN]
  284.  
  285. @dc{
  286.  
  287. Talk about how to use @tc[JOIN] to implement type hierarchies and
  288. heterarchies.
  289.  
  290. How to introduce @qu"punting"?  What syntax to use?  Bletch.
  291.  
  292. }
  293.  
  294. @section[Synonyms]
  295.  
  296. @iix[Synonyms] are objects whose behavior under generic operations
  297. may vary dynamically.
  298. @index[Call-by-name]
  299.  
  300. @info[NOTES="Special form"]
  301. @desc[(SYNONYM @i[expression]) @yl[] @i[synonym]]
  302. Yields a synonym for @i[expression.]
  303. If an operation is applied to the synonym,
  304. the @i[expression] is evaluated, yielding
  305. another object to which the operation will then be applied.
  306.  
  307. Again using the non-existent @tc[*OBJECT] and @tc[GET-HANDLER] primitives:
  308.   @begin[ProgramExample]
  309. (SYNONYM @i[exp])
  310.   @ce[]
  311. (LET ((THUNK (LAMBDA () @i[exp])))
  312.   (*OBJECT (LAMBDA ARGS (APPLY (THUNK) ARGS))
  313.            (LAMBDA (OP) ((GET-HANDLER (THUNK)) OP))))
  314.   @end[ProgramExample]
  315.     @BeginInset[Bug:]
  316.     @Timp[] 2.7 doesn't implement @tc[SYNONYM].
  317.     @EndInset[]
  318. @EndDesc[SYNONYM]
  319.  
  320. @dc{ Talk about using synonyms and @tc[JOIN] to implement objects
  321. whose behavior may be altered through time. }
  322.  
  323. @section[Example]
  324.  
  325. Hypothetical implementation of @tc[CONS]:
  326.  
  327. @begin[ProgramExample]
  328. (DEFINE (CONS THE-CAR THE-CDR)
  329.   (OBJECT NIL
  330.           ((PAIR? SELF) T)
  331.           ((CAR SELF) THE-CAR)
  332.           ((CDR SELF) THE-CDR)
  333.           (((SETTER CAR) SELF NEW-CAR) (SET THE-CAR NEW-CAR))
  334.           (((SETTER CDR) SELF NEW-CDR) (SET THE-CDR NEW-CDR))))
  335.  
  336. (DEFINE-PREDICATE PAIR?)
  337. (DEFINE-SETTABLE-OPERATION (CAR PAIR))
  338. (DEFINE-SETTABLE-OPERATION (CDR PAIR))
  339. @end[ProgramExample]
  340.  
  341. @dc{ Maybe insert the 6.001 queue example here. }
  342.